﻿using System;
using System.ComponentModel;
using System.Configuration;
using System.Data.SQLite;
using System.Threading;
using System.IO;
using System.Windows.Forms;
using TwinCAT.Ads;
using log4net;

namespace DBStorageFromADS
{
    public partial class MainForm : Form
    {
        private static log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        private bool isExit;
        private int ErrorCount;
        private TcAdsClient tcClient;
        private TcAdsSymbolInfoLoader symbolLoader;
        private int[] handlerDN;

        private int[] V_SJCG= new int[300];
        private int[] V_ResultL = new int[300];
        private int[] V_ResultR = new int[300];

        private bool Flag_GEMEI_END_L, Flag_GEMEI_END_L_last;
        private bool Flag_GEMEI_END_R, Flag_GEMEI_END_R_last;

        private string amsid = ConfigurationManager.AppSettings["AMSID"];
        private static int N = Convert.ToInt32(ConfigurationManager.AppSettings["Number"]);

        BackgroundWorker bwL = new BackgroundWorker();
        BackgroundWorker bwR = new BackgroundWorker();

        public MainForm()
        {
            InitializeComponent();
            this.Load += new EventHandler(MainForm_Load);
            this.FormClosing += new FormClosingEventHandler(MainForm_Closing);
            this.btnGetValues.Click += new EventHandler(btnGetValues_Click);
            this.btnSaveDataL.Click += new EventHandler(btnSaveDataL_Click);
            this.btnSaveDataR.Click += new EventHandler(btnSaveDataR_Click);

            bwL.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_InsertData_RunWorkerCompleted);
            bwR.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_InsertData_RunWorkerCompleted);

            isExit = false;

            ADSDBSQLite3.CreateTables();
            ResultAppendText("数据库存储路径：" + ADSDBSQLite3.dbDirPath + "\r\n");
        }


        private void MainForm_Load(object sender ,System.EventArgs e)
        {
            tcClient = new TcAdsClient();
            tcClient.Connect(amsid, 801);
            handlerDN = new int[3];


            //try
            //{
            //    AddDN();
            //    ResultAppendText("CreateSymbolInfoLoader And AdsNotificationEx Success!!\r\n");

            //}
            //catch (Exception err)
            //{
            //    ResultAppendText("CreateVariableHandle Or AdsNotificationEx Error:" + err.Message + "\r\n");
            //    ResultAppendText("After 5s Reconnect \r\n");
            //    Thread t = new Thread(new ThreadStart(ReConnect));
            //    t.Start();
            //}

            Thread tHandlerEndFlag = new Thread(new ThreadStart(HandlerEndFlag));
            tHandlerEndFlag.Start();
            log.Debug("tHandlerEndFlag.Start();");

        }

        private void HandlerEndFlag()
        {
            while(!isExit)
            {
                GetEndFlag();
                if (Flag_GEMEI_END_L && !Flag_GEMEI_END_L_last)
                {
                    ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + ": 捕获到割煤完成标志位-左(Cycle)\r\n");
                    log.Info("捕获到割煤完成标志位 - 左(Cycle)");
                    bwL.DoWork += new DoWorkEventHandler(bw_SaveData);
                    bwL.RunWorkerAsync("RESULT_L");                    
                }
                else if (Flag_GEMEI_END_R && !Flag_GEMEI_END_R_last)
                {
                    ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + ": 捕获到割煤完成标志位-右(Cycle)\r\n");
                    log.Info("捕获到割煤完成标志位 - 右(Cycle)");
                    bwR.DoWork += new DoWorkEventHandler(bw_SaveData);
                    bwR.RunWorkerAsync("RESULT_R");
                }
                Thread.Sleep(2000);
            }
                      
        }
        private void AddDN()
        {
            symbolLoader = tcClient.CreateSymbolInfoLoader();
            handlerDN[0] = tcClient.AddDeviceNotificationEx(".GEMEI_END_L", AdsTransMode.OnChange, 100, 0, lb_TextL, typeof(Boolean));
            handlerDN[1] = tcClient.AddDeviceNotificationEx(".GEMEI_END_R", AdsTransMode.OnChange, 100, 0, lb_TextR, typeof(Boolean));
      
            tcClient.AdsNotificationEx += new AdsNotificationExEventHandler(tcClient_AdsNotificationEx);
            
        }

        private void ReConnect()
        {
            Start: Thread.Sleep(5000);
            ResultAppendText("Start Reconnect \r\n");
            try 
            {
                AddDN();
                ResultAppendText("handlerDN: "+handlerDN[0].ToString()+" "+handlerDN[1].ToString()+" \r\n");
            }
            catch(Exception err)
            {
                ResultAppendText("CreateVariableHandle Or AdsNotificationEx Error:" + err.Message + "\r\n");
                ResultAppendText("After 5s Reconnect \r\n");
                goto Start;
            }
        }
        private  void MainForm_Closing(object sender,System.EventArgs e)
        {
            isExit = true;
            Thread.Sleep(200);
            tcClient.Dispose();
        }

        //rhTxtResult跨线程委托追加文字
        public delegate void AppedText(string resultText);

        public void ResAppedText(string resultText)
        {
            this.rhTxtResult.AppendText(resultText);
        }
        public void ResultAppendText(string resultText)
        {
            if (rhTxtResult.InvokeRequired)
            {
                this.Invoke(new AppedText(ResAppedText), resultText);               
            }
            else
            {
                this.rhTxtResult.AppendText(resultText);
            }
        }

        private void btnReadSymbolInfo_Click(object sender, EventArgs e)
        {

            TcAdsSymbolInfo symbol = symbolLoader.GetFirstSymbol(true);
            while (symbol != null)
            {
                    ResultAppendText(symbol.Name+"\r\n");
                    symbol = symbol.NextSymbol;
            }
        }

        private void btnGetValues_Click(object sender, EventArgs e)
        {
            GetData();
            ResultAppendText("===========================\r\nNo. - SJCG - Result_L - Result_R\r\n");
            for (int i = 0; i < N; i++)
            {
                ResultAppendText(i+" -- "+V_SJCG[i]+" -- "+V_ResultL[i] + " -- "+V_ResultR[i]+ "\r\n");
            }
        }

        private void GetData()
        {
           
            try
            {
                int num = (N + 1) * 2;
                // AdsStream which gets the data
                int hSJCG = tcClient.CreateVariableHandle(".SHIJICAIGAO");
                AdsStream dsSJCG = new AdsStream(num);
                BinaryReader brSJCG = new BinaryReader(dsSJCG);

                int hResL = tcClient.CreateVariableHandle(".RESULT_L");
                AdsStream dsResL = new AdsStream(num);
                BinaryReader brResL = new BinaryReader(dsResL);

                int hResR = tcClient.CreateVariableHandle(".RESULT_R");
                AdsStream dsResR = new AdsStream(num);
                BinaryReader brResR = new BinaryReader(dsResR);

                //read comlpete Array 
                tcClient.Read(hSJCG, dsSJCG);
                tcClient.Read(hResL, dsResL);
                tcClient.Read(hResR, dsResR);

                dsSJCG.Position = 0;
                dsResL.Position = 0;
                dsResR.Position = 0;

                for (int i = 0; i < N+1; i++)
                {
                    V_SJCG[i] = brSJCG.ReadInt16();
                    V_ResultL[i] = brResL.ReadInt16();
                    V_ResultR[i] = brResR.ReadInt16();
                }
            }
            catch (Exception err)
            {
                //MessageBox.Show(err.Message);
                ResultAppendText("GetData Error," + err.Message+"\r\n");
            }
        }

        private void GetEndFlag()
        {
            try
            {
                int hResultEndL = tcClient.CreateVariableHandle(".GEMEI_END_L");
                int hResultEndR = tcClient.CreateVariableHandle(".GEMEI_END_R");
  
                Flag_GEMEI_END_L_last = Flag_GEMEI_END_L;
                Flag_GEMEI_END_R_last = Flag_GEMEI_END_R;
                Flag_GEMEI_END_L = (bool)tcClient.ReadAny(hResultEndL, typeof(Boolean));
                Flag_GEMEI_END_R = (bool)tcClient.ReadAny(hResultEndR, typeof(Boolean));

                log.Debug("Flag_L:" + Flag_GEMEI_END_L.ToString()
                    + " , Flag_L_last:" + Flag_GEMEI_END_L_last.ToString()
                    + " , Flag_R:" + Flag_GEMEI_END_R.ToString()
                    + " , Flag_R_last:" + Flag_GEMEI_END_R_last.ToString());
                ErrorCount = 0;
            }
            catch (Exception err)
            {
                ErrorCount++;
                //ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")+"GetEndFlag Error," + err.Message + "\r\n"); ;
                log.Debug(err.ToString());
                if (ErrorCount > 10)
                {
                    log.Debug("ErrorCount > 5");
                    ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "ErrorCount > 5 App Exit");
                    Thread.Sleep(2000);
                    System.Environment.Exit(0);
                }
                Thread.Sleep(1000);
            }
        }
        private void btnSaveDataL_Click(object sender, EventArgs e)
        {
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")+ ": Save Data (L)Testing:\r\n");
            Insert_L_Data(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": Save Data (L)Testing End:\r\n");
        }

        private void btnSaveDataR_Click(object sender, EventArgs e)
        {
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": Save Data (R)Testing:\r\n");
            Insert_R_Data(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
            ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + ": Save Data (R)Testing End:\r\n");
        }

        public void Insert_L_Data(object nowtime)
        {
            Insert_Data_ToDB(nowtime, "SJCG", "RESULT_L");
        }

        public void Insert_R_Data(object nowtime)
        {
            Insert_Data_ToDB(nowtime, "SJCG", "RESULT_R");
        }

        public void Insert_Data_ToDB(object nowtime, params string[] tableName)
        {
            string now = (string)nowtime;

            SQLiteConnection conn = new SQLiteConnection(ADSDBSQLite3.dbPath);//创建数据库实例，指定文件位置  
            conn.Open();//打开数据库，若文件不存在会自动创建

            SQLiteTransaction tran = conn.BeginTransaction();//实例化一个事务  

            SQLiteCommand cmdTemp = new SQLiteCommand(conn);
            cmdTemp.Transaction = tran;
            foreach (var item in tableName)
            {
                cmdTemp.CommandText = ADSDBSQLite3.GenerateInsertSQL(item,N);
                cmdTemp.Parameters.AddRange(GenerateSQLiteParameter(now, item, N));
                cmdTemp.ExecuteNonQuery();
            }
            
            tran.Commit();//提交
            conn.Close();
        }
        public SQLiteParameter[] GenerateSQLiteParameter(string now, string table, int num)
        {
            SQLiteParameter[] sqlparamenter = new SQLiteParameter[num + 1];
            sqlparamenter[0] = new SQLiteParameter("@time", now);
            string s = "";
            string name = "";
            for (int i = 1; i <= num; i++)
            {
                s = Convert.ToString(i);
                name = table + s;
                if (table.Equals("SJCG")){
                    sqlparamenter[i] = new SQLiteParameter("@" + name, V_SJCG[i-1]);
                }
                else if (table.Equals("RESULT_L"))
                {
                    sqlparamenter[i] = new SQLiteParameter("@" + name, V_ResultL[i]);
                }
                else if (table.Equals("RESULT_R"))
                {
                    sqlparamenter[i] = new SQLiteParameter("@" + name, V_ResultR[i]);
                }
            }
            return sqlparamenter;
        }

        //数据保存完成后，在主界面显示完成信息
        void bw_InsertData_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ResultAppendText(e.Result.ToString());
            log.Info(e.Result.ToString());
        }

        //保存数据
        void bw_SaveData(object sender, DoWorkEventArgs e)
        {
            //获取参数
            string st = (string)e.Argument;
            string now = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            Thread.Sleep(100); // 延时100ms后

            GetData();
            
            if (st == "RESULT_R")
            {
                Insert_R_Data((object)now);
                e.Result = now + ": 实际采高-预测采高右数据存储完成\r\n";
            }
            else if (st == "RESULT_L")
            {
                //Thread.Sleep(4500);
                Insert_L_Data((object)now);
                e.Result = now + ": 实际采高-预测采高左数据存储完成\r\n";
            }
        }

        private void tcClient_AdsNotificationEx(object sender, AdsNotificationExEventArgs e)
        {
           Label lb = (Label)e.UserData;
            Type type = e.Value.GetType();
            if (type == typeof(string) || type.IsPrimitive)
            {
                SetLableText(lb, e.Value.ToString());
            }
            
            if ( e.NotificationHandle == handlerDN[0])
            {   if (e.Value.ToString() == "True")
                {
                    ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ")+" 捕获到割煤完成标志位-左\r\n");
                    bwL.DoWork += new DoWorkEventHandler(bw_SaveData);
                    bwL.RunWorkerAsync("RESULT_L");
                }
                
            }else if(e.NotificationHandle == handlerDN[1])
            {
                if (e.Value.ToString() == "True")
                {
                    ResultAppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + " 捕获到割煤完成标志位-右\r\n");
                    bwR.DoWork += new DoWorkEventHandler(bw_SaveData);
                    bwR.RunWorkerAsync("RESULT_R");
                }
            }
        }

        public delegate void SetText(Label l,string txt);
        private void SetlbText(Label l,string txt)
        {
            l.Text = txt;
        }
        public void SetLableText(Label l,string txt)
        {
            if (l.InvokeRequired)
            {
                this.Invoke(new SetText(SetlbText), l, txt);
            }
            else
            {
                SetlbText(l, txt);
            }
        }

        private void btnClearResult_Click(object sender, EventArgs e)
        {
            rhTxtResult.Clear();
        }
    }
}
